/** @file    PluginLoader.cpp
 *  @author  Alessandro Polo
 *  @version $Id: PluginLoader.cpp 2488 2010-05-21 01:48:27Z alex $
 *  @brief
 * File containing methods for the wosh::plugins::PluginLoader class.
 * The header for this class can be found in PluginLoader.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <framework/plugins/PluginLoader.h>

 #include <core/FileSystem.h>


#ifdef _OS_POSIX

#else
 #ifdef _OS_WINCE
 #else

 #endif
#endif

using namespace std;
namespace wosh {
 namespace plugins {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

PluginLoader::PluginLoader() : ObjectAllocator()
 {
	Object::setName( "PluginLoader" );

	Log.setIndent( 4 );
	Log.setLevel( LOG_INFO );

Log.setLevel( LOG_VERBOSE );

	Log(LOG_VERBOSE, " Setting default LibFolder [$ROOT/lib]" );
	this->libFolder.set( "$ROOT/lib" );

#ifdef _OS_POSIX
	Log(LOG_VERBOSE, " Setting default Extension [.so]" );
	this->pluginExtension = ".so";
#else
	Log(LOG_VERBOSE, " Setting default Extension [.dll]" );
	this->pluginExtension = ".dll";
#endif

 }

PluginLoader::~PluginLoader()
 {
	 Log(LOG_INFO, " Destroying Modules!" );
	 this->modules.free();
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT PluginLoader::preload( bool deep )
 {
	if ( !this->libFolder.isFolder() ) {
		Log(LOG_CRITICAL, ":preload(%s) FAILED Folder doesn't exists!", this->libFolder.getPathLocal().c_str() );
		return WRET_ERR_PARAM;
	 }
	vector<string> sourceFiles;
	WRESULT ret = FileSystem::getFilesOf( this->libFolder.getPathLocal(), sourceFiles, true, true, this->pluginExtension );
	if ( WFAILED(ret) || sourceFiles.empty() ) {
		Log(LOG_CRITICAL, ":preload() FAILED getting files of %s", "../lib" );
		return WRET_ERR_PARAM;
	 }

	string filename;
	std::vector<std::string>::iterator it;
	for ( it=sourceFiles.begin(); it!=sourceFiles.end(); ++it ) {

		PluginModule* module = new PluginModule();
		WRESULT ret = module->setLibraryFile(*it);
		if ( WFAILED(ret) ) {
			delete module;
			continue;
		 }
		if ( deep ) {
			module->loadInfo(true);
		 }

		this->modules.append(module);

	}

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

IReflection* PluginLoader::createObject( const std::string& object_type )
 {
	if ( object_type.empty() ) return NULL;

	this->modules.transactionBeginRead();
	ListT<PluginModule*>::Iterator it;
	ListT<PluginModule*>::ConstIterator it_end = this->modules.end();
	for ( it=this->modules.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( !(*it)->isModuleParsed() ) {
			(*it)->loadInfo(true);
		 }
		if ( !(*it)->supportsObjectType( object_type ) ) continue;
		if ( !(*it)->isModuleOpened() ) {
			(*it)->open();
		 }
		IReflection* obj = (*it)->alloc( object_type );
		this->modules.transactionEnd();
		return obj;
	 }
	this->modules.transactionEnd();

	return NULL;
 }

WRESULT PluginLoader::destroyObject( const std::string& obj_uuid )
 {
	if ( obj_uuid.empty() ) return WRET_ERR_PARAM;

	this->modules.transactionBeginRead();
	ListT<PluginModule*>::Iterator it;
	ListT<PluginModule*>::ConstIterator it_end = this->modules.end();
	for ( it=this->modules.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( !(*it)->isModuleOpened() ) continue;
		if ( !(*it)->getObjects().exists(obj_uuid) ) continue;
		WRESULT ret = (*it)->dealloc( obj_uuid );
		this->modules.transactionEnd();
		return ret;
	 }
	this->modules.transactionEnd();

	return WRET_ERR_INTERNAL;
 }

bool PluginLoader::supportObject( const std::string& object_type )
 {
	if ( object_type.empty() ) return false;

	this->modules.transactionBeginRead();
	ListT<PluginModule*>::ConstIterator it;
	ListT<PluginModule*>::ConstIterator it_end = this->modules.end();
	for ( it=this->modules.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( !(*it)->isModuleParsed() ) {
			(*it)->loadInfo(true);
		 }
		if ( !(*it)->supportsObjectType( object_type ) ) continue;
		this->modules.transactionEnd();
		return true;
	 }
	this->modules.transactionEnd();

	return false;
 }


int PluginLoader::getSupportedObjects( std::vector<std::string>& objects_list )
 {
	this->modules.transactionBeginRead();
	ListT<PluginModule*>::ConstIterator it;
	ListT<PluginModule*>::ConstIterator it_end = this->modules.end();
	for ( it=this->modules.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( !(*it)->isModuleParsed() ) {
			(*it)->loadInfo(true);
		 }
		std::vector<string>::iterator it_ot;
		std::vector<string>::iterator it_ot_end = (*it)->getObjectTypes().end();
		for ( it_ot=(*it)->getObjectTypes().begin(); it_ot!=it_ot_end; it_ot++ ) {
			objects_list.push_back(*it_ot);
		 }
	 }
	this->modules.transactionEnd();

	return objects_list.size();
 }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT PluginLoader::setLibraryFolder( const string& library_folder )
 {
	this->libFolder.set(library_folder);
	if ( !this->libFolder.isFolder() ) {
		Log(LOG_CRITICAL, ":setLibraryFolder(%s) FAILED Folder doesn't exists!", this->libFolder.getPathLocal().c_str() );
		return WRET_ERR_PARAM;
	 }
	return WRET_OK;
 }

WRESULT PluginLoader::setPluginFileExtension( const string& plugin_file_extension )
 {
	this->pluginExtension = plugin_file_extension;
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace plugins
}; // namespace wosh
